package org.zebias.udpnettydemo.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFactory;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;
import io.netty.util.NetUtil;
import io.netty.util.internal.ThreadExecutorMap;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

/**
 * @ClassName UdpClient
 * @Description Udp客户端
 * @Author zebias
 * @Date 2021/3/1 17:04
 * @Version 1.0
 **/
public class UdpClient {

    // 单播
    public void runSingle() throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioDatagramChannel.class)
                    // 广播
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new UdpClientHandler());
            Channel channel = b.bind(groupAddrss.getPort()).sync().channel();
            // 向网段内所有的机器广播
                channel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("客户端给你的", CharsetUtil.UTF_8),groupAddrss)).sync();
                    // 客户端等待15s用于接收服务端的应答消息，然后退出并释放资源
                    if (!channel.closeFuture().await(15000)) {
                        System.out.println("查询超时!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }

    public UdpClient() {
    }

    private InetSocketAddress groupAddrss;
    public UdpClient(InetSocketAddress groupAddrss){
        this.groupAddrss = groupAddrss;
    }

    // 组播
    public void runMulticast(String netCard) throws Exception{
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            NetworkInterface ni = netCard == null?NetUtil.LOOPBACK_IF:NetworkInterface.getByName(netCard);
            Enumeration<InetAddress> addresses = ni.getInetAddresses();
            InetAddress localAddress = null;
            while (addresses.hasMoreElements()) {
                InetAddress address = addresses.nextElement();
                if (address instanceof Inet4Address){
                    localAddress = address;
                }
            }
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioDatagramChannel.class)
//                    .channelFactory(() -> new NioDatagramChannel(InternetProtocolFamily.IPv4))
                    // 组播
                    .localAddress(localAddress,groupAddrss.getPort())
                    .option(ChannelOption.IP_MULTICAST_IF,ni )
                    .option(ChannelOption.SO_REUSEADDR,true )
                    .handler(new UdpClientHandler());
            Channel channel = b.bind().sync().channel();
            // 向网段内所有的机器广播
            channel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("客户端给你的", CharsetUtil.UTF_8), groupAddrss)).sync();
            // 客户端等待15s用于接收服务端的应答消息，然后退出并释放资源
            if (!channel.closeFuture().await(15000)) {
                System.out.println("查询超时!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }

    // 广播
    public void runBoradCast() {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioDatagramChannel.class)
                    // 广播
                    .option(ChannelOption.SO_BROADCAST, true)
                    .handler(new UdpClientHandler());
            Channel channel = b.bind(0).sync().channel();
            // 向网段内所有的机器广播
            channel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("客户端给你的", CharsetUtil.UTF_8),groupAddrss)).sync();
            // 客户端等待15s用于接收服务端的应答消息，然后退出并释放资源
            if (!channel.closeFuture().await(15000)) {
                System.out.println("查询超时!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        // 单播
        //new UdpClient().runSingle(8888);

        // 组播
//        System.setProperty("java.net.preferIPv4Stack", "true");
//        InetSocketAddress inetSocketAddress = new InetSocketAddress("224.2.1.1",9000);
        // 指定网卡
//        new UdpClient(inetSocketAddress).runMulticast("eth2");

        // 广播
        InetSocketAddress inetSocketAddress2 = new InetSocketAddress("192.168.188.255",7686);
        new UdpClient(inetSocketAddress2).runBoradCast();
    }
}
